package com.cencat.common.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.cencat.common.context.UserContext;
import com.cencat.common.utils.TenantUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * MyBatis-Plus元数据处理器
 * 自动填充创建时间、更新时间、创建人、更新人、租户ID等字段
 * 
 * @author cencat
 * @since 2024-01-01
 */
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    private static final Logger log = LoggerFactory.getLogger(MyMetaObjectHandler.class);

    /** 创建时间字段名 */
    private static final String CREATE_TIME = "createTime";
    
    /** 更新时间字段名 */
    private static final String UPDATE_TIME = "updateTime";
    
    /** 创建人字段名 */
    private static final String CREATE_BY = "createBy";
    
    /** 更新人字段名 */
    private static final String UPDATE_BY = "updateBy";
    
    /** 租户ID字段名 */
    private static final String TENANT_ID = "tenantId";
    
    /** 版本号字段名 */
    private static final String VERSION = "version";
    
    /** 逻辑删除字段名 */
    private static final String DELETED = "deleted";

    /**
     * 插入时自动填充
     * 
     * @param metaObject 元对象
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.debug("开始插入填充，实体类: {}", metaObject.getOriginalObject().getClass().getName());
        
        LocalDateTime now = LocalDateTime.now();
        Long currentUserId = getCurrentUserId();
        
        // 填充创建时间
        if (metaObject.hasSetter(CREATE_TIME)) {
            Object createTime = getFieldValByName(CREATE_TIME, metaObject);
            if (createTime == null) {
                setFieldValByName(CREATE_TIME, now, metaObject);
                log.debug("自动填充创建时间: {}", now);
            }
        }
        
        // 填充更新时间
        if (metaObject.hasSetter(UPDATE_TIME)) {
            Object updateTime = getFieldValByName(UPDATE_TIME, metaObject);
            if (updateTime == null) {
                setFieldValByName(UPDATE_TIME, now, metaObject);
                log.debug("自动填充更新时间: {}", now);
            }
        }
        
        // 填充创建人
        if (metaObject.hasSetter(CREATE_BY) && currentUserId != null) {
            Object createBy = getFieldValByName(CREATE_BY, metaObject);
            if (createBy == null) {
                setFieldValByName(CREATE_BY, currentUserId, metaObject);
                log.debug("自动填充创建人: {}", currentUserId);
            }
        }
        
        // 填充更新人
        if (metaObject.hasSetter(UPDATE_BY) && currentUserId != null) {
            Object updateBy = getFieldValByName(UPDATE_BY, metaObject);
            if (updateBy == null) {
                setFieldValByName(UPDATE_BY, currentUserId, metaObject);
                log.debug("自动填充更新人: {}", currentUserId);
            }
        }
        
        // 填充租户ID
        Long currentTenantIdLong = getCurrentTenantId();
        if (metaObject.hasSetter(TENANT_ID) && currentTenantIdLong != null) {
            Object tenantId = getFieldValByName(TENANT_ID, metaObject);
            if (tenantId == null) {
                setFieldValByName(TENANT_ID, currentTenantIdLong, metaObject);
                log.debug("自动填充租户ID: {}", currentTenantIdLong);
            }
        }
        
        // 填充版本号（乐观锁）
        if (metaObject.hasSetter(VERSION)) {
            Object version = getFieldValByName(VERSION, metaObject);
            if (version == null) {
                setFieldValByName(VERSION, 1, metaObject);
                log.debug("自动填充版本号: 1");
            }
        }
        
        // 填充逻辑删除标识
        if (metaObject.hasSetter(DELETED)) {
            Object deleted = getFieldValByName(DELETED, metaObject);
            if (deleted == null) {
                setFieldValByName(DELETED, 0, metaObject);
                log.debug("自动填充逻辑删除标识: 0");
            }
        }
        
        log.debug("插入填充完成");
    }

    /**
     * 更新时自动填充
     * 
     * @param metaObject 元对象
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.debug("开始更新填充，实体类: {}", metaObject.getOriginalObject().getClass().getName());
        
        LocalDateTime now = LocalDateTime.now();
        Long currentUserId = getCurrentUserId();
        
        // 填充更新时间
        if (metaObject.hasSetter(UPDATE_TIME)) {
            setFieldValByName(UPDATE_TIME, now, metaObject);
            log.debug("自动填充更新时间: {}", now);
        }
        
        // 填充更新人
        if (metaObject.hasSetter(UPDATE_BY) && currentUserId != null) {
            setFieldValByName(UPDATE_BY, currentUserId, metaObject);
            log.debug("自动填充更新人: {}", currentUserId);
        }
        
        log.debug("更新填充完成");
    }

    /**
     * 获取当前用户ID
     * 
     * @return 当前用户ID，如果未登录则返回null
     */
    private Long getCurrentUserId() {
        try {
            return UserContext.getCurrentUserId();
        } catch (Exception e) {
            log.debug("获取当前用户ID失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取当前租户ID
     * 
     * @return 当前租户ID，如果未设置则返回null
     */
    private Long getCurrentTenantId() {
        try {
            return TenantUtils.getCurrentTenantId();
        } catch (Exception e) {
            log.debug("获取当前租户ID失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 检查字段是否存在且为空
     * 
     * @param fieldName 字段名
     * @param metaObject 元对象
     * @return 是否需要填充
     */
    private boolean needFill(String fieldName, MetaObject metaObject) {
        return metaObject.hasSetter(fieldName) && getFieldValByName(fieldName, metaObject) == null;
    }

    /**
     * 安全设置字段值
     * 
     * @param fieldName 字段名
     * @param fieldVal 字段值
     * @param metaObject 元对象
     */
    private void safeSetFieldValue(String fieldName, Object fieldVal, MetaObject metaObject) {
        try {
            if (metaObject.hasSetter(fieldName)) {
                setFieldValByName(fieldName, fieldVal, metaObject);
            }
        } catch (Exception e) {
            log.warn("设置字段值失败: fieldName={}, fieldVal={}, error={}", fieldName, fieldVal, e.getMessage());
        }
    }

    /**
     * 批量填充字段
     * 
     * @param metaObject 元对象
     * @param fillMap 填充映射
     */
    private void batchFill(MetaObject metaObject, java.util.Map<String, Object> fillMap) {
        fillMap.forEach((fieldName, fieldValue) -> {
            if (needFill(fieldName, metaObject)) {
                safeSetFieldValue(fieldName, fieldValue, metaObject);
                log.debug("批量填充字段: {}={}", fieldName, fieldValue);
            }
        });
    }

    /**
     * 获取填充策略
     * 
     * @return 填充策略枚举
     */
    public enum FillStrategy {
        /** 仅在字段为空时填充 */
        FILL_IF_NULL,
        /** 强制填充（覆盖原值） */
        FORCE_FILL,
        /** 跳过填充 */
        SKIP_FILL
    }

    /**
     * 字段填充配置
     */
    public static class FieldFillConfig {
        /** 字段名 */
        private String fieldName;
        /** 填充值 */
        private Object fillValue;
        /** 填充策略 */
        private FillStrategy strategy;
        /** 是否启用 */
        private boolean enabled;

        public FieldFillConfig(String fieldName, Object fillValue, FillStrategy strategy) {
            this.fieldName = fieldName;
            this.fillValue = fillValue;
            this.strategy = strategy;
            this.enabled = true;
        }

        // Getters and Setters
        public String getFieldName() { return fieldName; }
        public void setFieldName(String fieldName) { this.fieldName = fieldName; }
        public Object getFillValue() { return fillValue; }
        public void setFillValue(Object fillValue) { this.fillValue = fillValue; }
        public FillStrategy getStrategy() { return strategy; }
        public void setStrategy(FillStrategy strategy) { this.strategy = strategy; }
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
    }
}